#include <stdio.h>
#include <stdlib.h>

#include "libbozorth3/bozorth.h"
#include "libmindtct/lfs.h"
#include "libnbis.h"


/* Default {x,y,t} representation is "NIST internal", not M1 */
//TODO: convert to local
int m1_xyt = 0;


/******************************************************************************
func nbisPgmToMinutiae
	detect minutiae on pgm image and prepare it to use in bozorth3 algorithm
input
	gpm - pointer to pgm image source data
out
	xytPacked - pointer to output buffer
return
	Negative on error
	count of <struct xyt_packed>
******************************************************************************/
int nbisPgmToMinutiae( unsigned char* pgm, struct xyt_packed* xytPacked ){
	
	int res;
	int i;
	
	MINUTIAE* minutiae;
	int* quality_map;
	int* direction_map;
	int* low_contrast_map;
	int* low_flow_map;
	int* high_curve_map;
	int map_w;
	int map_h;
	unsigned char* binData;
	int binWidth;
	int binHeight;
	int binDepth;
	int inputWidth;
	int inputHeight;
	double ippmm;
	
	struct xyt_struct* xyt;
	struct xytq_struct xytq;
	
	inputHeight = 270;
	inputWidth = 144;
	
	
	ippmm = DEFAULT_PPI / (double)MM_PER_INCH;
	
	//minutiae detect
	res = get_minutiae(
		&minutiae,         //points to a structure containing the detected minutiae
		&quality_map,      //resulting integrated image quality map
		&direction_map,    //resulting direction map
		&low_contrast_map, //resulting low contrast map
		&low_flow_map,     //resulting low ridge flow map
		&high_curve_map,   //resulting high curvature map
		&map_w,            //width (in blocks) of image maps
		&map_h,            //height (in blocks) of image maps
		&binData,          //points to binarized image data
		&binWidth,         //width (in pixels) of binarized image
		&binHeight,        //height (in pixels) of binarized image
		&binDepth,         //pixel depth (in bits) of binarized image
		pgm,               //grayscale fingerprint image data
		inputWidth,        //width (in pixels) of the grayscale image
		inputHeight,       //height (in pixels) of the grayscale image
		8,                 //pixel depth (in bits) of the grayscale image
		ippmm,             //the scan resolution (in pixels/mm) of the grayscale image
		&lfsparms_V2       //parameters and thresholds for controlling LFS
	);
	
	if( res ){
		printf( "get_minutiae error: %i\n", res );
		return -1;
	}
	
	//fill xytq struct from minutiae data
	xytq.nrows = minutiae->num;
	for( i = 0; i < minutiae->num; i++ ){
		//lfs2m1_minutia_XYT( &xytq.xcol[i], &xytq.ycol[i], &xytq.thetacol[i], minutiae->list[i] );
		lfs2nist_minutia_XYT( &xytq.xcol[i], &xytq.ycol[i], &xytq.thetacol[i], minutiae->list[i], inputWidth, inputHeight );
		xytq.qualitycol[i] = sround( minutiae->list[i]->reliability * 100.0 );
		if ( i == MAX_FILE_MINUTIAE ) break;
	}
	
	//free unneeded data
	free_minutiae( minutiae );
	
	free( quality_map      );
	free( direction_map    );
	free( low_contrast_map );
	free( low_flow_map     );
	free( high_curve_map   );
	free( binData          );
	
	//convert xytq to xyt
	xyt = bz_prune( &xytq );//need free()!!!
	if( !xyt ){
		printf( "bz_prune return null\n" );
		return -2;
	}
	
	//pack data
	for( i = 0; i < xyt->nrows; i++ ){
		xytPacked[i].x = xyt->xcol[i];
		xytPacked[i].y = xyt->ycol[i];
		xytPacked[i].t = xyt->thetacol[i];
	}
	
	res = xyt->nrows;
	free( xyt );
	return res;
}
/***************************************
func nbisBozorth3Packed
	calculate match score using bozorth3
return
	match score
***************************************/
int nbisBozorth3Packed( struct xyt_packed* packedProbe, int probeCount, struct xyt_packed* packedGallery, int galleryCount ){
	
	int i;
	int score;
	struct xyt_struct probe;
	struct xyt_struct gallery;
	
	probe.nrows = probeCount;
	for( i = 0; i < probeCount; i++ ){
		probe.xcol[i]     = packedProbe[i].x;
		probe.ycol[i]     = packedProbe[i].y;
		probe.thetacol[i] = packedProbe[i].t;
	}
	
	gallery.nrows = galleryCount;
	for( i = 0; i < galleryCount; i++ ){
		gallery.xcol[i]     = packedGallery[i].x;
		gallery.ycol[i]     = packedGallery[i].y;
		gallery.thetacol[i] = packedGallery[i].t;
	}
	
	score = bozorth_main( &probe, &gallery );
	
	return score == QQ_OVERFLOW_SCORE ? 0 : score;
}

